import {Select, Input} from 'antd';
import {useState, useEffect, useMemo, useRef, useCallback} from 'react';
import './index.css';

const styleBox = {width: '100%'};

let index = 1;
const initOpts = () => {
	return Array(20).fill(null).map(() => {
		const k = index++;
		return {label: `label${k}`, value: `value${k}`};
	});
};

const BaseSelect = ({
	placeholder,
	panelHolder = '请输入关键词搜索',
	// option字段映射
	keys = {
		label: "label",
		value: "value",
	},
	// http请求参数的字段名
	searchField = 'name',
	// 每页显示多少条数据
	pageSize = 15,
	// 未提供接口，则启用本地模式
	httpApi,
	// 接口请求时的固定参数
	staticParam,
	// multiple | tags
	mode,
	// 展开面板时是否自动请求数据
	autoRequest = true,
	// 原始下拉数据
	originOpts = [],
	// 下拉框初始值
	initialValue = null
}) => {
	const coverValue = useCallback((value) => {
		// 基础数据类型，直接与originOpts匹配
		if (value && typeof value !== 'object') {
			return originOpts.find(item => item[keys.value] === value);
		} else {
			return value;
		};
	}, [originOpts]);
	// 初始化初始值
	const initValue = useCallback(() => {
		if (['multiple', 'tags'].includes(mode)) {
			return Array.isArray(initialValue) ? initialValue.map(coverValue) : [];
		} else {
			return coverValue(initialValue);
		}
	}, [initialValue]);

	const [page, setPage] = useState(1);
	const [loading, setLoading] = useState(false);
	const [value, setValue] = useState(initValue());
	const [searchValue, setSearchValue] = useState(null);
	const searchRef = useRef(null);
	const [open, setOpen] = useState(false);
	// 初始下拉，接口异步搜索，以及本地搜索得到的数据
	const [baseOpts, setBaseOpts] = useState([...originOpts]);
	const resData = useRef(null);
	const fullOpts = useMemo(() => {
		let v = value || [];
		const id = keys.value;
		v = Array.isArray(v) ? v : [v];
		v = v.filter((item) => item[id]);
		const opts = baseOpts.filter((opt) => {
			return v.every((dd) => opt[id] !== dd[id]);
		});
		return [...v, ...opts];
	}, [value, baseOpts]);
	// console.log(fullOpts, 'fullOpts');
	const loadOption = useCallback(async () => {
		if (!httpApi) return;
		setLoading(true);
		const id = keys.value;
		const {data} = resData.current = await httpApi({
			page,
			pageSize,
			[searchField]: searchValue,
			...staticParam
		});
		setBaseOpts([
			...baseOpts,
			// 过滤掉源下拉中已经存在的数据
			...data.filter(v => baseOpts.every(dd => dd[id] !== v[id]))
		]);
		setLoading(false);
	}, [baseOpts]);
	const style = {padding: '12px', borderBottom: '1px solid #e8e8e8'};
	return (<div className="base-select" style={styleBox} >
		<Select
			style={{width: 220}}
			loading={loading}
			value={value}
			open={open}
			mode={mode}
			onDropdownVisibleChange={async visible => {
				setOpen(visible);
				// 初始调用接口，获取数据
				if (visible && baseOpts.length == originOpts.length && autoRequest) {
					loadOption();
				}
			}}
			onPopupScroll={async (e) => {
				const {target} = e;
				// 判断是否滑动到底部 滚动条顶部距离 + 下拉栏展示高度 = 滚动总高度
				if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
					setPage(page + 1);
					// 滑动到底部实现分页加载逻辑
					if (fullOpts.length < resData.current.total) loadOption();
				}
			}}
			options={fullOpts}
			placeholder={placeholder}
			dropdownRender={
				(menu) => (<div>
					<div className="top" style={style} >
						<Input
							ref={node => {
								searchRef.current = node;
								if (node) node.focus();
							}}
							defaultValue={searchValue}
							placeholder={panelHolder}
							onChange={(e) => {
								setPage(1);
								setSearchValue(e);
								loadOption();
							}}
						/>
					</div>
					<div className="content" > {menu} </div>
				</div>)
			}
			onChange={(v) => {
				setValue(v);
			}}
		/>
	</div>);
};

const httpApi = async () => {
	return new Promise((resolve) => {
		setTimeout(() => {
			resolve({data: initOpts(), total: 40});
		}, 1000);
	});
};
const SelectDemo = () => {
	const value = 'value6';
	const originOpts = [{label: 'label2', value: 'value2'}, {label: 'label6', value: 'value6'}];
	return (<div className="select-demo" >
		<BaseSelect placeholder="请选择" httpApi={httpApi} initialValue={value} originOpts={originOpts} />
	</div>);
};

export default SelectDemo;